home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
CUGUK
/
APPLICAT
/
C050.ZIP
/
SFSSRC.ZIP
/
SFS.SRC
/
AS
/
AS_SPJ.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-04
|
14KB
|
588 lines
/***************************************************************
as_spj.c Spherical projection routines
for astronomy (as) subsystem
Copyright (c) 1991, Ted A. Campbell
Bywater Software
P. O. Box 4023
Duke Station
Durham, NC 27706
email: tcamp@hercules.acpub.duke.edu
Copyright and Permissions Information:
All U.S. and international copyrights are claimed by the
author. The author grants permission to use this code
and software based on it under the following conditions:
(a) in general, the code and software based upon it may be
used by individuals and by non-profit organizations; (b) it
may also be utilized by governmental agencies in any country,
with the exception of military agencies; (c) the code and/or
software based upon it may not be sold for a profit without
an explicit and specific permission from the author, except
that a minimal fee may be charged for media on which it is
copied, and for copying and handling; (d) the code must be
distributed in the form in which it has been released by the
author; and (e) the code and software based upon it may not
be used for illegal activities.
***************************************************************/
#include "stdio.h"
#include "math.h"
#include "bw.h"
#include "as.h"
#ifdef __STDC__
#include "malloc.h"
#else
extern char * malloc();
#endif
/***************************************************************
spj_readspd() Read an SPJ datafile
***************************************************************/
spj_readspd( datafile, start, end )
char *datafile;
struct spj_pt *start, *end;
{
FILE *data;
register int c;
static char read_buffer[ 128 ];
static int co;
static double la, lo, di;
struct spj_pt *current, *new;
/* Open the datafile */
if ( ( data = fopen( datafile, "rb" )) == NULL )
{
sprintf( bw_ebuf, "Failed to open datafile %s", datafile );
bw_error( bw_ebuf );
return BW_ERROR;
}
else
{
sprintf( bw_ebuf, "Reading spherical projection datafile %s",
datafile );
bw_message( bw_ebuf );
}
/* Get storage for the first point */
if ( ( current = ( struct spj_pt *) malloc( sizeof( struct spj_pt ) )) == NULL )
{
sprintf( bw_ebuf, "Failed to allocate memory reading %s", datafile );
bw_error( bw_ebuf );
return BW_ERROR;
}
#ifdef OLD_DEBUG
else
{
sprintf( bw_ebuf, "Memory for %s allocated ok",
datafile );
bw_message( bw_ebuf );
}
#endif
start->next = current;
/* Read the data from the file */
c = 0;
while( feof( data ) == 0 )
{
as_fgets( read_buffer, 127, data );
sscanf( read_buffer, "%d%lf%lf%lf", &co, &la, &lo, &di );
current->code = co;
current->latitude = la;
current->longitude = lo;
current->radius = di;
#ifdef OLD_DEBUG
sprintf( bw_ebuf, "[pr:] spj_readsd(): %d: %.1lf %.1lf",
c, la, lo );
bw_message( bw_ebuf );
#endif
/* Now get a new 'current' */
if ( ( new = (struct spj_pt *)
malloc( sizeof( struct spj_pt ) )) == 0 )
{
sprintf( bw_ebuf, "Failed to allocate memory reading %s", datafile );
bw_error( bw_ebuf );
return BW_ERROR;
}
#ifdef OLD_DEBUG
else
{
sprintf( bw_ebuf, "Memory for %s allocated ok",
datafile );
bw_message( bw_ebuf );
}
#endif
/* Reassign linkage from current to new */
if ( feof( data ) == FALSE )
{
current->next = new;
current = new;
current->next = end;
}
if ( ferror( data ) != FALSE )
{
sprintf( bw_ebuf, "Failed reading %s", datafile );
bw_error( bw_ebuf );
return BW_ERROR;
}
++c;
}
fclose( data );
return TRUE;
}
/***************************************************************
spj_calc() Calculate a linked set of SPJ
point structures
***************************************************************/
spj_calc( start, end, vlat, vlon, vdis, forced_radius, rotation, mode, poll )
struct spj_pt *start, *end;
double vlat, vlon, vdis;
double forced_radius;
double rotation;
int mode;
int (*poll)();
{
struct spj_pt *current;
static double x, y;
static int side;
register int d;
double radius;
#ifdef DEBUG
if ( ( vlat < -90.0 ) || ( vlat > 90.0 ))
{
sprintf( bw_ebuf, "[pr:] spj_calc() received vlat = %lf", vlat );
bw_error( bw_ebuf );
return;
}
if ( ( vlon < -180.0 ) || ( vlon > 180.0 ))
{
sprintf( bw_ebuf, "[pr:] spj_calc() received vlon = %lf", vlon );
bw_error( bw_ebuf );
return;
}
if ( vdis < 0.0 )
{
sprintf( bw_ebuf, "[pr:] spj_calc() received vdis = %lf", vdis );
bw_error( bw_ebuf );
return;
}
if ( ( rotation < 0.0 ) || ( rotation > 360.0 ))
{
sprintf( bw_ebuf, "[pr:] spj_calc() received rotation = %lf", rotation );
bw_error( bw_ebuf );
return;
}
if ( ( mode < 0 ) || ( mode > 2 ))
{
sprintf( bw_ebuf, "[pr: spj_calc() received mode = %d", mode );
bw_error( bw_ebuf );
return;
}
#endif
d = 0;
current = start->next;
while( current != end )
{
++d;
if ( forced_radius == 0.0 )
{
radius = current->radius;
}
else
{
radius = forced_radius;
}
#ifdef OLD_DEBUG
sprintf( bw_ebuf, " calculate %d: lat %0.2lf, lon %0.2lf, rad %0.2lf >>",
d, current->latitude, current->longitude, radius );
bw_message( bw_ebuf );
kb_rx();
#endif
spj_point( current->latitude, current->longitude,
radius, vlat, vlon, vdis, rotation,
mode, &x, &y, &side );
current->x = x;
current->y = y;
current->side = side;
#ifdef OLD_DEBUG
sprintf( bw_ebuf, " x = %0.2lf, y = %0.2lf, v = %d >>",
current->x * ACC_FAC,
current->y * ACC_FAC,
current->side );
bw_message( bw_ebuf );
kb_rx();
#endif
/* call poll function */
(*poll) ();
current = current->next;
}
}
/***************************************************************
spj_point() Calculate a spherical projection point
This routine is, in a sense, the heart of the Space
Flight Simulator and other spherical-projection programs
related to it, such as the Space Flight Atlas.
***************************************************************/
spj_point( plat, plon, prad, vlat, vlon, vdis, rotation, mode, x, y, side )
double plat; /* latitude of point in object coordinates */
double plon; /* longitude of point in object coordinates */
double prad; /* "radius" i.e., distance from center of
object, of the point */
double vlat; /* latitude of viewer */
double vlon; /* longitude of viewer */
double vdis; /* distance of viewer from center of object */
double rotation; /* rotation of object in degrees, counter-
clockwise;
int mode; /* mode of calculation, i.e., side(s) to calculate */
double *x; /* return x viewer coordinate in degrees of arc */
double *y; /* return y viewer coordinate in degrees of arc */
int *side; /* return side of sphere */
{
static double old_vlat = 361.0;
static double old_vlon = 361.0;
static double old_vdis = -1.0;
static double old_plat = 361.0;
static double old_plon = 361.0;
static double old_prad = -1.0;
static double old_rot = 361.0;
static double x_lon = 361.0;
static double x_rsin, x_rcos;
static double x_cosplat, x_sinplat;
static double x_cosvlat, x_sinvlat;
static double x_angrad;
double x_cosc, x_cosl;
double x_temp, y_temp;
#ifdef OLD_DEBUG
sprintf( bw_ebuf, "[pr:] spj_point() received: plat %0.2lf, plon %0.2lf, prad %0.2lf >>",
plat, plon, prad );
bw_message( bw_ebuf );
kb_rx();
sprintf( bw_ebuf, "[pr:] spj_point() received: vlat %0.2lf, vlon %0.2lf, vdis %0.2lf >>",
vlat, vlon, vdis );
bw_message( bw_ebuf );
kb_rx();
sprintf( bw_ebuf, "[pr:] spj_point() received: rot %0.2lf, mode %d >>",
rotation, mode );
bw_message( bw_ebuf );
kb_rx();
#endif
#ifdef DEBUG
if ( ( vlat < -90.0 ) || ( vlat > 90.0 ))
{
sprintf( bw_ebuf, "[pr:] spj_calc() received vlat = %lf", vlat );
bw_error( bw_ebuf );
return;
}
if ( ( vlon < -180.0 ) || ( vlon > 180.0 ))
{
sprintf( bw_ebuf, "[pr:] spj_calc() received vlon = %lf", vlon );
bw_error( bw_ebuf );
return;
}
if ( vdis < 0.0 )
{
sprintf( bw_ebuf, "[pr:] spj_calc() received vdis = %lf", vdis );
bw_error( bw_ebuf );
return;
}
if ( ( plat < -90.0 ) || ( plat > 90.0 ))
{
sprintf( bw_ebuf, "[pr:] spj_calc() received plat = %lf", plat );
bw_error( bw_ebuf );
return;
}
if ( ( plon < -180.0 ) || ( plon > 180.0 ))
{
sprintf( bw_ebuf, "[pr:] spj_calc() received plon = %lf", plon );
bw_error( bw_ebuf );
return;
}
if ( prad < 0.0 )
{
sprintf( bw_ebuf, "[pr:] spj_calc() received prad = %lf", prad );
bw_error( bw_ebuf );
return;
}
if ( ( rotation < 0.0 ) || ( rotation > 360.0 ))
{
sprintf( bw_ebuf, "[pr:] spj_calc() received rotation = %lf", rotation );
bw_error( bw_ebuf );
return;
}
if ( ( mode < 0 ) || ( mode > 2 ))
{
sprintf( bw_ebuf, "[pr: spj_calc() received mode = %d", mode );
bw_error( bw_ebuf );
return;
}
#endif
/* if longitude is changed, calculate its sine and cosine */
if ( plon != old_plon )
{
x_lon = spj_meridian( vlon, plon );
old_plon = plon;
#ifdef OLD_DEBUG
bw_message( "[pr:] spj_point() recalculated plon" );
kb_rx();
#endif
}
/* if viewer latitude is changed, calculate its sine and cosine */
if ( vlat != old_vlat )
{
x_cosvlat = vpt_cos( vlat );
x_sinvlat = vpt_sin( vlat );
old_vlat = vlat;
#ifdef OLD_DEBUG
bw_debug( "[pr:] spj_point() recalculated vlat" );
#endif
}
/* if point latitude is changed, calculate its sine and cosine */
if ( plat != old_plat )
{
x_cosplat = vpt_cos( plat );
x_sinplat = vpt_sin( plat );
old_plat = plat;
#ifdef OLD_DEBUG
bw_debug( "[pr:] spj_point() recalculated plat" );
#endif
}
/* calculations to determine side */
x_cosl = vpt_cos( x_lon ) * x_cosplat;
x_cosc = x_sinvlat * x_sinplat + x_cosvlat * x_cosl;
/* Note side of sphere, and return if this side is not
to be calculated now */
if ( x_cosc < 0 )
{
*side = SPJ_FARSIDE;
if ( mode == SPJ_NEARSIDE )
{
return;
}
}
else
{
*side = SPJ_NEARSIDE;
if ( mode == SPJ_FARSIDE )
{
return;
}
}
/* if point radius or viewer distance is changed, recalculate
the angular radius */
if ( ( prad != old_prad ) || ( vdis != old_vdis ))
{
x_angrad = spj_angrad( vdis, prad );
old_prad = prad;
old_vdis = vdis;
#ifdef OLD_DEBUG
bw_message( "[pr:] spj_point() recalculated angular radius" );
kb_rx();
#endif
}
/* Assign unrotated values */
*x = x_angrad * ( x_cosplat * vpt_sin( x_lon ) );
*y = x_angrad * ( x_cosvlat * x_sinplat - x_sinvlat * x_cosl );
/* if rotation has changed, recalculate its sine and cosine */
if ( rotation != old_rot )
{
x_rsin = vpt_sin( rotation );
x_rcos = vpt_cos( rotation );
old_rot = rotation;
#ifdef OLD_DEBUG
bw_message( "[pr:] spj_point() recalculated rotation" );
kb_rx();
#endif
}
/* Rotate the image */
x_temp = *x;
y_temp = *y;
*x = 0.0 - (( x_temp * x_rcos ) - ( y_temp * x_rsin ));
*y = ( x_temp * x_rsin ) + ( y_temp * x_rcos );
#ifdef OLD_DEBUG
sprintf( bw_ebuf, "[pr:] spj_point() returns: x %0.2lf, y %0.2lf, side %d >>",
*x, *y, *side );
bw_message( bw_ebuf );
kb_rx();
#endif
}
/***************************************************************
spj_meridian() Calculate the distance in degrees
between a point's longitude and the
viewer's longitude
***************************************************************/
double
spj_meridian( vlon, plon )
double vlon; /* viewer's longitude */
double plon; /* point longitude */
{
double retval;
retval = vlon - plon;
if ( retval < -180 )
{
retval += 360;
}
if ( retval > 180 )
{
retval -= 360;
}
return retval;
}
/***************************************************************
spj_angrad() Calculate the angular radius of an object
given the radius of the object and the
distance to the viewer
***************************************************************/
double
spj_angrad( distance, radius )
double distance, radius;
{
#ifdef DEBUG
if ( distance == 0.0 )
{
sprintf( bw_ebuf, "[pr:] spj_angrad() received distance = %lf",
distance );
bw_error( bw_ebuf );
return 1.0;
}
#endif
return ( RAD_DEG * atan( radius / distance ));
}
/***************************************************************
spj_degfix() Fix degrees, i.e., 0 < d < 360
***************************************************************/
double
spj_degfix( n )
double n;
{
double retval;
retval = n;
while ( retval < 0 )
{
retval += 360;
}
while ( retval > 360 )
{
retval -= 360;
}
#ifdef OLD_DEBUG
sprintf( bw_ebuf, "spj_degfix(): rec %.2lf, ret %.2lf", n, retval );
bw_debug( bw_ebuf );
#endif
return retval;
}
/***************************************************************
as_fgets() Gets a string from a bitstream,
excluding strings that begin with ';'
This function acts exactly as the standard Unix/C
fgets() function, except that it rejects lines that
begin with a semicolon. This alllows us to imbed
comment lines in as datafiles by beginning them with
a semicolon.
***************************************************************/
char *
as_fgets( s, n, stream )
char *s;
int n;
FILE *stream;
{
char *r;
r = (char *) 1;
s[ 0 ] = ';';
while( s[ 0 ] == ';' )
{
r = fgets( s, n, stream );
if ( r == NULL )
{
return NULL;
}
}
return r;
}